/* Orbas:
 *     A open source CORBA Specification implementation from Huihoo.
 *
 * Copyright 2002-2003 Huihoo.org, Inc. All Right Reserved.
 *
 * This software is licensed under LGPL license.
 * See terms of license at gnu.org.
 *
 * For more information, visit:
 *
 * http://www.huihoo.org/orbas
 */

package org.huihoo.orbas.poa;

/**
 * <p>Description: </p>
 * POA Implement of CORBA POA.
 * <p>Copyright (c) 2003</p>
 * <p>Company: <a href="http://www.huihoo.org/orbas">huihoo.org</a></p>
 * @author <a href="http://www.huihoo.org/~cocia">Cocia Lin(cocia@163.com)</a>
 * @see <a href="http://www.huihoo.org/orbas">http://www.huihoo.org/orbas</a>
 * @version 1.0
 */

import java.util.Collection;
import java.util.Hashtable;

import org.huihoo.orbas.orb.ORB;
import org.huihoo.orbas.orb.ior.IorParser;
import org.huihoo.orbas.poa.policy.IdAssignmentPolicyImpl;
import org.huihoo.orbas.poa.policy.IdUniquenessPolicyImpl;
import org.huihoo.orbas.poa.policy.ImplicitActivationPolicyImpl;
import org.huihoo.orbas.poa.policy.LifespanPolicyImpl;
import org.huihoo.orbas.poa.policy.RequestProcessingPolicyImpl;
import org.huihoo.orbas.poa.policy.ServantRetentionPolicyImpl;
import org.huihoo.orbas.poa.policy.ThreadPolicyImpl;
import org.huihoo.orbas.util.Logger;
import org.huihoo.orbas.util.LoggerFactory;
import org.omg.CORBA.Object;
import org.omg.CORBA.Policy;
import org.omg.CORBA.portable.InputStream;
import org.omg.CORBA.portable.OutputStream;
import org.omg.CORBA.portable.ResponseHandler;
import org.omg.PortableServer.AdapterActivator;
import org.omg.PortableServer.IdAssignmentPolicy;
import org.omg.PortableServer.IdAssignmentPolicyValue;
import org.omg.PortableServer.IdUniquenessPolicy;
import org.omg.PortableServer.IdUniquenessPolicyValue;
import org.omg.PortableServer.ImplicitActivationPolicy;
import org.omg.PortableServer.ImplicitActivationPolicyValue;
import org.omg.PortableServer.LifespanPolicy;
import org.omg.PortableServer.LifespanPolicyValue;
import org.omg.PortableServer.POA;
import org.omg.PortableServer.POAManager;
import org.omg.PortableServer.RequestProcessingPolicy;
import org.omg.PortableServer.RequestProcessingPolicyValue;
import org.omg.PortableServer.Servant;
import org.omg.PortableServer.ServantManager;
import org.omg.PortableServer.ServantRetentionPolicy;
import org.omg.PortableServer.ServantRetentionPolicyValue;
import org.omg.PortableServer.ThreadPolicy;
import org.omg.PortableServer.ThreadPolicyValue;

public class POAImpl extends org.omg.CORBA.LocalObject implements POA, OrbasPoa {
	// ~
	// the_name()
	private String name;
	// the_children()
	private Hashtable children = new Hashtable();
	// the_parent()
	private org.omg.PortableServer.POA parent;
	// the_POAManager()
	private POAManager poaManager;
	// the orbas orb instance
	private org.huihoo.orbas.orb.ORB orb;
	// policies attribute var
	// private IdAssignmentPolicy idAssignmentPolicy;
	private boolean system_id = true; // new poa default.
	private boolean user_id = false;
	// private IdUniquenessPolicy idUniquenessPolicy;
	private boolean unique_id = true; // new poa default.
	private boolean multiple_id = false;
	// private ImplicitActivationPolicy implicitActivationPolicy;
	private boolean implicit_activation = false;
	private boolean no_implicit_activation = true; // new poa default.
	// private LifespanPolicy lifespanPolicy;
	private boolean _transient = true; // new poa default.
	private boolean persistent = false;
	// private RequestProcessingPolicy requestProcessingPolicy;
	private boolean use_active_object_map_only = true; // new poa default.
	private boolean use_default_servant = false;
	private boolean use_servant_manager = false;
	// private ServantRetentionPolicy servantRetentionPolicy;
	private boolean retain = true; // new poa default.
	private boolean non_retain = false;
	// private ThreadPolicy threadPolicy;
	private boolean orb_ctrl_model = true; // new poa default.
	private boolean single_thread_model = false;
	private boolean main_thread_model = false; // corba 2.3 later

	// policies attribute end

	// active servant object map(aom)
	// ActiveObjectMap aom = new ActiveObjectMap();
	java.util.Hashtable aom = new java.util.Hashtable();
	java.util.Hashtable aomReverse = new java.util.Hashtable();
	// poa's id for orb's poa map
	private byte[] id;
	// Logger tool.
	private static Logger logger = LoggerFactory.getLogger("POA");

	//
	public POAImpl() {
		logger.debug("POA:POAImpl()");
		/*
		 * Common Object Request Broker Architecture (CORBA), v3.0 July 2002
		 * (page 11-6) The root POA has the following policies. \u2022 Thread
		 * Policy: ORB_CTRL_MODEL \u2022 Lifespan Policy: TRANSIENT \u2022
		 * Object Id Uniqueness Policy: UNIQUE_ID \u2022 Id Assignment Policy:
		 * SYSTEM_ID \u2022 Servant Retention Policy: RETAIN \u2022 Request
		 * Processing Policy: USE_ACTIVE_OBJECT_MAP_ONLY \u2022 Implicit
		 * Activation Policy: IMPLICIT_ACTIVATION
		 */
		// create default policies for RootPOA
		Policy threadPolicy = create_thread_policy(org.omg.PortableServer.ThreadPolicyValue.ORB_CTRL_MODEL);
		Policy lifespanPolicy = create_lifespan_policy(org.omg.PortableServer.LifespanPolicyValue.TRANSIENT);
		Policy idUniquenessPolicy = create_id_uniqueness_policy(org.omg.PortableServer.IdUniquenessPolicyValue.UNIQUE_ID);
		Policy idAssignmentPolicy = create_id_assignment_policy(org.omg.PortableServer.IdAssignmentPolicyValue.SYSTEM_ID);
		Policy implicitActivationPolicy = create_implicit_activation_policy(org.omg.PortableServer.ImplicitActivationPolicyValue.IMPLICIT_ACTIVATION);
		Policy servantRetentionPolicy = create_servant_retention_policy(org.omg.PortableServer.ServantRetentionPolicyValue.RETAIN);
		Policy requestProcessingPolicy = create_request_processing_policy(org.omg.PortableServer.RequestProcessingPolicyValue.USE_ACTIVE_OBJECT_MAP_ONLY);

		Policy[] policies = new Policy[7];
		policies[0] = threadPolicy;
		policies[1] = lifespanPolicy;
		policies[2] = idUniquenessPolicy;
		policies[3] = idAssignmentPolicy;
		policies[4] = implicitActivationPolicy;
		policies[5] = servantRetentionPolicy;
		policies[6] = requestProcessingPolicy;

		initPOA(null, this, "RootPOA", new POAManagerImpl(), policies);

	}

	public POAImpl(ORB orb, POA parent, String adapter_name,
			POAManager a_POAManager, Policy[] policies) {
		logger.debug("POA:POAImpl(...)");
		initPOA(orb, parent, adapter_name, a_POAManager, policies);

	}

	protected void initPOA(ORB orb, POA parent, String adapter_name,
			POAManager a_POAManager, Policy[] policies) {
		logger.debug("POA:initPOA(...)");
		// if POAManager is empty then create a new one,
		// else set it for the new POA
		if (a_POAManager == null) {
			a_POAManager = new POAManagerImpl();
		}
		this.poaManager = a_POAManager;
		// save policies setting
		for (int i = 0; i < policies.length; i++) {
			switch (policies[i].policy_type()) {
			case org.omg.PortableServer.THREAD_POLICY_ID.value:
				if (((ThreadPolicy) policies[i]).value().value() == ThreadPolicyValue._ORB_CTRL_MODEL) {
					orb_ctrl_model = true; // true
					single_thread_model = false;
					main_thread_model = false;
				} else if (((ThreadPolicy) policies[i]).value().value() == ThreadPolicyValue._SINGLE_THREAD_MODEL) {
					orb_ctrl_model = false;
					single_thread_model = true; // true
					main_thread_model = false;

				} else {
					orb_ctrl_model = false;
					single_thread_model = false;
					main_thread_model = true; // true
				}
				break;
			case org.omg.PortableServer.LIFESPAN_POLICY_ID.value:
				if (((LifespanPolicy) policies[i]).value().value() == LifespanPolicyValue._TRANSIENT) {
					_transient = true;
					persistent = false;
				} else {
					_transient = false;
					persistent = true;
				}
				break;
			case org.omg.PortableServer.ID_UNIQUENESS_POLICY_ID.value:
				if (((IdUniquenessPolicy) policies[i]).value().value() == IdUniquenessPolicyValue._UNIQUE_ID) {
					unique_id = true;
					multiple_id = false;
				} else {
					unique_id = false;
					multiple_id = true;
				}
				break;
			case org.omg.PortableServer.ID_ASSIGNMENT_POLICY_ID.value:
				if (((IdAssignmentPolicy) policies[i]).value().value() == IdAssignmentPolicyValue._SYSTEM_ID) {
					system_id = true;
					user_id = false;
				} else {
					system_id = false;
					user_id = true;
				}
				break;
			case org.omg.PortableServer.IMPLICIT_ACTIVATION_POLICY_ID.value:
				if (((ImplicitActivationPolicy) policies[i]).value().value() == ImplicitActivationPolicyValue._NO_IMPLICIT_ACTIVATION) {
					no_implicit_activation = true;
					implicit_activation = false;
				} else {
					no_implicit_activation = false;
					implicit_activation = true;
				}
				break;
			case org.omg.PortableServer.SERVANT_RETENTION_POLICY_ID.value:
				if (((ServantRetentionPolicy) policies[i]).value().value() == ServantRetentionPolicyValue._RETAIN) {
					retain = true;
					non_retain = false;
				} else {
					retain = false;
					non_retain = true;
				}
				break;
			case org.omg.PortableServer.REQUEST_PROCESSING_POLICY_ID.value:
				if (((RequestProcessingPolicy) policies[i]).value().value() == RequestProcessingPolicyValue._USE_ACTIVE_OBJECT_MAP_ONLY) {
					use_active_object_map_only = true;
					use_default_servant = false;
					use_servant_manager = false;
				} else if (((RequestProcessingPolicy) policies[i]).value()
						.value() == RequestProcessingPolicyValue._USE_DEFAULT_SERVANT) {
					use_active_object_map_only = false;
					use_default_servant = true;
					use_servant_manager = false;

				}

				else {
					use_active_object_map_only = false;
					use_default_servant = false;
					use_servant_manager = true;

				}
				break;
			default:
				// error policy.
			}
		}
		// set parent POA
		this.parent = parent;
		// set name
		this.name = adapter_name;
		// generate id for poa
		this.id = UniqueIdGenerator.generateId().getBytes();
		// set the orb
		this.orb = orb;

	}

	public POA create_POA(String adapter_name, POAManager a_POAManager,
			Policy[] policies)
			throws org.omg.PortableServer.POAPackage.AdapterAlreadyExists,
			org.omg.PortableServer.POAPackage.InvalidPolicy {
		// check policies first:
		// must not contain the wrong policy in array policies
		int[] policyType = new int[policies.length];
		for (int i = 0; i < policyType.length; i++) {
			policyType[i] = policies[i].policy_type();
		}
		// check for duplicate policy
		for (int i = 0; i < policyType.length; i++) {
			for (int j = 0; j < policyType.length; j++) {
				if (i != j && policyType[i] == policyType[j]) {
					throw new org.omg.PortableServer.POAPackage.InvalidPolicy();
				}
			}
		}

		// check:must not have same poa in the_children()
		if (children.containsKey(adapter_name)) {
			throw new org.omg.PortableServer.POAPackage.AdapterAlreadyExists(
					"POA name:" + adapter_name
							+ " already exist in its parent POA:" + the_name());
		}

		// create new POA
		return new POAImpl(orb, this, adapter_name, a_POAManager, policies);
	}

	public POA find_POA(String adapter_name, boolean activate_it)
			throws org.omg.PortableServer.POAPackage.AdapterNonExistent {
		// check for the poa exist
		synchronized (children) {
			if (children.containsKey(adapter_name)) {
				return (POA) children.get(adapter_name);
			}

			// handle for poa not exist
			// 1.get AdapterActivator and active a poa
			// 2.if not AdapterActivator then throw exception
			// here is minimum corba,so no AdapterActivator support.
			throw new org.omg.PortableServer.POAPackage.AdapterNonExistent(
					"POA[name:" + adapter_name + "] not exist.");
		}

	}

	public void destroy(boolean etherealize_objects, boolean wait_for_completion) {
		/** @todo Implement this org.omg.PortableServer.POAOperations method */
		throw new java.lang.UnsupportedOperationException(
				"Method destroy() not yet implemented.");
	}

	/**
	 * Minimum CORBA:Method create_thread_policy() not yet implemented.
	 * 
	 * @param value
	 * @return ThreadPolicy
	 */
	public ThreadPolicy create_thread_policy(ThreadPolicyValue value) {
		return new ThreadPolicyImpl(value);
	}

	public LifespanPolicy create_lifespan_policy(LifespanPolicyValue value) {
		return new LifespanPolicyImpl(value);
	}

	public IdUniquenessPolicy create_id_uniqueness_policy(
			IdUniquenessPolicyValue value) {
		return new IdUniquenessPolicyImpl(value);
	}

	public IdAssignmentPolicy create_id_assignment_policy(
			IdAssignmentPolicyValue value) {
		return new IdAssignmentPolicyImpl(value);
	}

	/**
	 * Minimum CORBA:Method create_implicit_activation_policy() not yet
	 * implemented.
	 * 
	 * @param value
	 * @return ImplicitActivationPolicy
	 */
	public ImplicitActivationPolicy create_implicit_activation_policy(
			ImplicitActivationPolicyValue value) {
		return new ImplicitActivationPolicyImpl(value);
	}

	/**
	 * Minimum CORBA:Method create_servant_retention_policy() not yet
	 * implemented.
	 * 
	 * @param value
	 * @return ServantRetentionPolicy
	 */
	public ServantRetentionPolicy create_servant_retention_policy(
			ServantRetentionPolicyValue value) {
		return new ServantRetentionPolicyImpl(value);
	}

	/**
	 * Minimum CORBA:Method create_request_processing_policy() not yet
	 * implemented.
	 * 
	 * @param value
	 * @return RequestProcessingPolicy
	 */
	public RequestProcessingPolicy create_request_processing_policy(
			RequestProcessingPolicyValue value) {
		return new RequestProcessingPolicyImpl(value);
	}

	public String the_name() {
		return new String(this.name);
	}

	public POA the_parent() {
		return parent;
	}

	public POA[] the_children() {
		synchronized (children) {
			Collection collec = children.values();
			return (POA[]) collec.toArray(new POA[children.size()]);
		}
	}

	public POAManager the_POAManager() {
		return poaManager;
	}

	public AdapterActivator the_activator() {
		throw new java.lang.UnsupportedOperationException(
				"Minimum CORBA:Method the_activator() not yet implemented.");
	}

	public void the_activator(AdapterActivator the_activator) {
		/** @todo Implement this org.omg.PortableServer.POAOperations method */
		throw new java.lang.UnsupportedOperationException(
				"Method the_activator() not yet implemented.");
	}

	public ServantManager get_servant_manager()
			throws org.omg.PortableServer.POAPackage.WrongPolicy {
		throw new java.lang.UnsupportedOperationException(
				"Minimum CORBA:Method get_servant_manager() not yet implemented.");
	}

	public void set_servant_manager(ServantManager imgr)
			throws org.omg.PortableServer.POAPackage.WrongPolicy {
		throw new java.lang.UnsupportedOperationException(
				"Minimum CORBA:Method set_servant_manager() not yet implemented.");
	}

	public Servant get_servant()
			throws org.omg.PortableServer.POAPackage.NoServant,
			org.omg.PortableServer.POAPackage.WrongPolicy {
		throw new java.lang.UnsupportedOperationException(
				"Minimum CORBA:Method get_servant() not yet implemented.");
	}

	public void set_servant(Servant p_servant)
			throws org.omg.PortableServer.POAPackage.WrongPolicy {
		throw new java.lang.UnsupportedOperationException(
				"Minimum CORBA:Method set_servant() not yet implemented.");
	}

	public byte[] activate_object(Servant p_servant)
			throws org.omg.PortableServer.POAPackage.ServantAlreadyActive,
			org.omg.PortableServer.POAPackage.WrongPolicy {
		// check policy first
		if (!retain || !system_id) {
			throw new org.omg.PortableServer.POAPackage.WrongPolicy(
					"policy:RETAIN and SYSTEM_ID required.");
		}
		// if UNIQUE_ID policy exist
		// and the servent in active object map,then throw exception

		if (unique_id && aom.contains(p_servant)) {
			throw new org.omg.PortableServer.POAPackage.ServantAlreadyActive();
		}
		// generate new oid and put servant into active object map(aom)
		byte[] oid = UniqueIdGenerator.generateId().getBytes();
		ObjectKey oKey = new ObjectKey(id, oid);
		// logger.debug("Object mapping:poaid="+id+",oid="+oid+",value="+p_servant);
		aom_put(oKey.getObjectKey(), p_servant);

		// set delegate
		orb.set_delegate(p_servant);

		// Object returned
		return oid;
	}

	public void activate_object_with_id(byte[] oid, Servant p_servant)
			throws org.omg.PortableServer.POAPackage.ServantAlreadyActive,
			org.omg.PortableServer.POAPackage.ObjectAlreadyActive,
			org.omg.PortableServer.POAPackage.WrongPolicy {
		// check policy first
		if (!retain) {
			throw new org.omg.PortableServer.POAPackage.WrongPolicy(
					"policy:RETAIN required.");
		}
		// when has policy:SYSTEM_ID
		if (system_id) {
			// check oid:if it generated by system.
			// true:UniqueIdGenerator.generateId().getBytes().length == 8
			if (oid.length != 8) {
				throw new org.omg.CORBA.BAD_PARAM();
			}
		}
		// put servant into active object map(aom)
		ObjectKey oKey = new ObjectKey(this.id, oid);
		// logger.debug("Object mapping:poaid="+id+",oid="+oid+",value="+p_servant);
		aom_put(oKey.getObjectKey(), p_servant);
		// set delegate
		orb.set_delegate(p_servant);
	}

	protected void aom_put(java.lang.Object key, java.lang.Object object) {
		// put servant into active object map(aom)
		aom.put(key, object);
		// if policy unique_id==true then make a link of servent<=>oid
		if (unique_id) {
			aomReverse.put(object, key);
		}

	}

	public void deactivate_object(byte[] oid)
			throws org.omg.PortableServer.POAPackage.ObjectNotActive,
			org.omg.PortableServer.POAPackage.WrongPolicy {
		/** @todo Implement this org.omg.PortableServer.POAOperations method */
		throw new java.lang.UnsupportedOperationException(
				"Method deactivate_object() not yet implemented.");
	}

	public Object create_reference(String intf)
			throws org.omg.PortableServer.POAPackage.WrongPolicy {
		// check policy first
		if (!system_id) {
			throw new org.omg.PortableServer.POAPackage.WrongPolicy(
					"policy:SYSTEM_ID required.");
		}
		// generate a new Object ID and create a new reference.
		byte[] oid = UniqueIdGenerator.generateId().getBytes();
		ObjectKey oKey = new ObjectKey(this.id, oid);
		IorParser parser = orb.createIor(oKey.getObjectKey().getBytes(), intf);

		org.omg.CORBA.Object obj = parser.getObject();

		return obj;
	}

	public Object create_reference_with_id(byte[] oid, String intf)
			throws org.omg.PortableServer.POAPackage.WrongPolicy {
		// when has policy:SYSTEM_ID
		if (system_id) {
			// check oid:if it generated by system.
			// true:UniqueIdGenerator.generateId().getBytes().length == 8
			if (oid.length != 8) {
				throw new org.omg.CORBA.BAD_PARAM();
			}
		}
		// create a new reference.
		IorParser parser = orb.createIor(oid, intf);
		org.omg.CORBA.Object obj = parser.getObject();
		//
		return obj;
	}

	/**
	 * This operation requires the USE_DEFAULT_SERVANT policy or a combination
	 * of the RETAIN policy and either the UNIQUE_ID or IMPLICIT_ACTIVATION
	 * policies if invoked outside the context of an operation dispatched by
	 * this POA. If this operation is not invoked in the context of executing a
	 * request on the specified servant and the policies specified previously
	 * are not present, the WrongPolicy exception is raised. This operation has
	 * four possible behaviors. 1. If the POA has both the RETAIN and the
	 * UNIQUE_ID policy and the specified servant is active, the Object Id
	 * associated with that servant is returned. 2. If the POA has both the
	 * RETAIN and the IMPLICIT_ACTIVATION policy and either the POA has the
	 * MULTIPLE_ID policy or the specified servant is not active, the servant is
	 * activated using a POA-generated Object Id and the Interface Id associated
	 * with the servant, and that Object Id is returned. 3. If the POA has the
	 * USE_DEFAULT_SERVANT policy, the servant specified is the default servant,
	 * and the operation is being invoked in the context of executing a request
	 * on the default servant, then the ObjectId associated with the current
	 * invocation is returned. 4. Otherwise, the ServantNotActive exception is
	 * raised. from 11-43
	 * 
	 * @param p_servant
	 * @return byte[]
	 * @throws org.omg.PortableServer.POAPackage.ServantNotActive
	 * @throws org.omg.PortableServer.POAPackage.WrongPolicy
	 */
	public byte[] servant_to_id(Servant p_servant)
			throws org.omg.PortableServer.POAPackage.ServantNotActive,
			org.omg.PortableServer.POAPackage.WrongPolicy {
		logger.debug("POA:servant_to_id(...)");
		// check policy first
		if (!use_default_servant && !(retain && unique_id)
				&& !(retain && implicit_activation)) {
			throw new org.omg.PortableServer.POAPackage.WrongPolicy();
		}
		// handle for 4 situation
		// 1)
		synchronized (aom) {
			if (unique_id && aom.containsValue(p_servant)) {
				// return object id
				return ((ObjectKey) aomReverse.get(p_servant)).getObjectId();
			}
			// 2)
			if (implicit_activation) {
				if (multiple_id || !aom.containsValue(p_servant)) {
					// create and activate
					byte[] oid = UniqueIdGenerator.generateId().getBytes();
					ObjectKey oKey = new ObjectKey(this.id, oid);
					// String[] ids = p_servant._all_interfaces(this, null);
					// logger.debug("Object mapping:poaid="+new
					// String(id)+",oid="+new
					// String(oid)+",value="+p_servant+",repid "+ids[0]);
					aom_put(oKey.getObjectKey(), p_servant);

					// set delegate
					orb.set_delegate(p_servant);

					return oid;
				}
			}
		}
		// 3)when has use_default_servant policy

		// 4)else throw exception
		throw new org.omg.PortableServer.POAPackage.ServantNotActive();
	}

	/**
	 * This operation requires the RETAIN policy and either the UNIQUE_ID or
	 * IMPLICIT_ACTIVATION policies if invoked outside the context of an
	 * operation dispatched by this POA. If this operation is not invoked in the
	 * context of executing a request on the specified servant and the policies
	 * specified previously are not present the WrongPolicy exception is raised.
	 * This operation has four possible behaviors. 1. If the POA has both the
	 * RETAIN and the UNIQUE_ID policy and the specified servant is active, an
	 * object reference encapsulating the information used to activate the
	 * servant is returned. 2. If the POA has both the RETAIN and the
	 * IMPLICIT_ACTIVATION policy and either the POA has the MULTIPLE_ID policy
	 * or the specified servant is not active, the servant is activated using a
	 * POA-generated Object Id and the Interface Id associated with the servant,
	 * and a corresponding object reference is returned. 3. If the operation was
	 * invoked in the context of executing a request on the specified servant,
	 * the reference associated with the current invocation is returned. 4.
	 * Otherwise, the ServantNotActive exception is raised. from 11-43
	 * 
	 * @param p_servant
	 * @return org.omg.CORBA.Object
	 * @throws org.omg.PortableServer.POAPackage.ServantNotActive
	 * @throws org.omg.PortableServer.POAPackage.WrongPolicy
	 */
	public Object servant_to_reference(Servant p_servant)
			throws org.omg.PortableServer.POAPackage.ServantNotActive,
			org.omg.PortableServer.POAPackage.WrongPolicy {
		logger.debug("POA:servant_to_reference(...)");
		// check policy first
		if (!(retain && unique_id) && !(retain && implicit_activation)) {
			throw new org.omg.PortableServer.POAPackage.WrongPolicy();
		}
		// handle for 4 situations
		// 1)
		synchronized (aom) {
			if ((retain && unique_id) && aom.containsValue(p_servant)) {
				// create a new reference to servant
				String oKey = ((String) aomReverse.get(p_servant));
				return servant_to_reference_with_id(oKey, p_servant);
			}

			// 2)
			if ((retain && implicit_activation)
					&& (multiple_id || !aom.containsValue(p_servant))) {
				// create a new reference to servant
				byte[] oid = servant_to_id(p_servant);
				// byte[] oid = UniqueIdGenerator.generateId().getBytes();
				ObjectKey oKey = new ObjectKey(this.id, oid);
				// aom_put(oKey.getObjectKey(), p_servant);
				return servant_to_reference_with_id(oKey.getObjectKey(),
						p_servant);
			}
		}
		// 3)

		// 4)else throw exception
		throw new org.omg.PortableServer.POAPackage.ServantNotActive();
	}

	protected org.omg.CORBA.Object servant_to_reference_with_id(String oidKey,
			Servant p_servant) {
		String[] ids = p_servant._all_interfaces(this, null);
		IorParser parser = orb.createIor(oidKey.getBytes(), ids[0]);

		org.omg.CORBA.Object obj = parser.getObject();

		// set delegate
		orb.set_delegate(p_servant);

		//
		return obj;

	}

	/**
	 * This operation requires the RETAIN policy or the USE_DEFAULT_SERVANT
	 * policy. If neither policy is present, the WrongPolicy exception is
	 * raised. If the POA has the RETAIN policy and the specified object is
	 * present in the Active Object Map, this operation returns the servant
	 * associated with that object in the Active Object Map. Otherwise, if the
	 * POA has the USE_DEFAULT_SERVANT policy and a default servant has been
	 * registered with the POA, this operation returns the default servant.
	 * Otherwise, the ObjectNotActive exception is raised. If the object
	 * reference was not created by this POA, the WrongAdapter exception is
	 * raised.
	 * 
	 * @param reference
	 * @return org.omg.PortableServer.Servant
	 * @throws org.omg.PortableServer.POAPackage.ObjectNotActive
	 * @throws org.omg.PortableServer.POAPackage.WrongPolicy
	 */
	public Servant reference_to_servant(Object reference)
			throws org.omg.PortableServer.POAPackage.ObjectNotActive,
			org.omg.PortableServer.POAPackage.WrongPolicy {
		logger.debug("POA:reference_to_servant(...)");
		// check for policy first
		// This operation requires the RETAIN policy or the USE_DEFAULT_SERVANT
		// policy.
		if (!retain && !use_default_servant) {
			throw new org.omg.PortableServer.POAPackage.WrongPolicy();
		}
		if (retain) {
			try {
				byte[] oid = reference_to_id(reference);
				ObjectKey oKey = new ObjectKey(this.id, oid);
				synchronized (aom) {
					if (aom.containsKey(oKey.getObjectKey())) {
						return (Servant) aom.get(oKey.getObjectKey());
					}
				}
			} catch (org.omg.PortableServer.POAPackage.WrongAdapter exwa) {
				throw new org.omg.PortableServer.POAPackage.ObjectNotActive();
			}

		} // return default servant if it exist.
		else if (use_default_servant) {
			try {
				synchronized (this) {
					if (this.get_servant() != null) {
						return this.get_servant();
					}
				}

			} catch (org.omg.PortableServer.POAPackage.NoServant exns) {
				throw new org.omg.PortableServer.POAPackage.ObjectNotActive();
			}

		}
		// else throw exception
		throw new org.omg.PortableServer.POAPackage.ObjectNotActive();
	}

	public byte[] reference_to_id(Object reference)
			throws org.omg.PortableServer.POAPackage.WrongAdapter,
			org.omg.PortableServer.POAPackage.WrongPolicy {
		logger.debug("POA:reference_to_id(...)");
		org.omg.CORBA.portable.ObjectImpl objectImpl = (org.omg.CORBA.portable.ObjectImpl) reference;
		//
		if (objectImpl == null) {
			// report an error
			throw new org.omg.PortableServer.POAPackage.WrongAdapter(
					"POA: Not a CORBA Object.");
		}
		org.huihoo.orbas.orb.ObjRefDelegate delegate = (org.huihoo.orbas.orb.ObjRefDelegate) (objectImpl
				._get_delegate());
		if (delegate == null) {
			// report an error
			throw new org.omg.PortableServer.POAPackage.WrongAdapter(
					"POA: Not a CORBA Object.Can NOT get delegate");
		}
		IorParser parser = delegate.getParser();

		String strObjectKey = new String(parser.getObjectKey());
		// check for right object key format
		// "poaid/objectid"
		if (strObjectKey.indexOf("/") == -1) {
			throw new org.omg.PortableServer.POAPackage.WrongAdapter(
					"POA: Malformed object key");
		}
		ObjectKey oKey = new ObjectKey(strObjectKey);
		// check for:the servant must be in this poa.
		if (!oKey.getObjectId().equals(this.id)) {
			throw new org.omg.PortableServer.POAPackage.WrongAdapter();
		}
		//
		return oKey.getObjectId();
	}

	public Servant id_to_servant(byte[] oid)
			throws org.omg.PortableServer.POAPackage.ObjectNotActive,
			org.omg.PortableServer.POAPackage.WrongPolicy {
		logger.debug("POA:id_to_servant(...)");
		// check for policy first
		if (!retain && !use_default_servant) {
			throw new org.omg.PortableServer.POAPackage.WrongPolicy();
		}
		// when retian policy and servant exist
		if (retain) {
			ObjectKey oKey = new ObjectKey(this.id, oid);
			synchronized (aom) {
				if (aom.containsKey(oKey.getObjectKey())) {
					return (Servant) aom.get(oKey.getObjectKey());
				}
			}
		} else if (use_default_servant) {
			// when policy use_default_servant
			try {
				synchronized (this) {
					if (this.get_servant() != null) {
						return this.get_servant();
					}
				}
			} catch (org.omg.PortableServer.POAPackage.NoServant exns) {
				throw new org.omg.PortableServer.POAPackage.ObjectNotActive();
			}

		}
		//
		throw new org.omg.PortableServer.POAPackage.ObjectNotActive();
	}

	public Object id_to_reference(byte[] oid)
			throws org.omg.PortableServer.POAPackage.ObjectNotActive,
			org.omg.PortableServer.POAPackage.WrongPolicy {
		logger.debug("POA:id_to_servant(...)");
		// check for policy first
		if (!retain) {
			throw new org.omg.PortableServer.POAPackage.WrongPolicy();
		}
		//
		ObjectKey oKey = new ObjectKey(this.id, oid);
		if (aom.containsKey(oKey.getObjectKey())) {
			try {
				return servant_to_reference((Servant) aom.get(oKey
						.getObjectKey()));
			} catch (org.omg.PortableServer.POAPackage.ServantNotActive exsna) {
				throw new org.omg.PortableServer.POAPackage.ObjectNotActive();
			}

		}
		// else throw exception
		throw new org.omg.PortableServer.POAPackage.ObjectNotActive();
	}

	public OutputStream invoke(byte[] oid, String method, InputStream is,
			ResponseHandler handler) throws org.omg.CORBA.OBJECT_NOT_EXIST {
		logger.debug("POA:invoke(...) " + method + ", Object id is "
				+ new String(oid));
		// obtain the servant
		// ObjectKey oKey = new ObjectKey(this.id, oid);
		try {
			Servant servant = id_to_servant(oid);
			// String[] ids = servant._all_interfaces(this, null);
			// logger.debug("RepId is "+ids[0]);
			// invoke the servant method
			RequestProcessor processor = new RequestProcessor();
			RequestEntry entry = new RequestEntry(servant, method, is, handler);
			processor.init(this, entry);
			// process.
			processor.process();
			// return servant._invoke(method, is, handler);
			return entry.getOutputStream();
		} catch (org.omg.PortableServer.POAPackage.ObjectNotActive exena) {
			exena.printStackTrace();
			throw new org.omg.CORBA.OBJECT_NOT_EXIST();
		} catch (org.omg.PortableServer.POAPackage.WrongPolicy exwp) {
			exwp.printStackTrace();
			throw new org.omg.CORBA.OBJECT_NOT_EXIST();
		}
	}

	public void setOrb(ORB orb) {
		this.orb = orb;
		// for Root POA use only
		if (the_name().equals("RootPOA")) {
			orb.registerPoa(this, new String(id));
		}

	}

}